package top.jnaw.jee.platform.controller.basics.extend;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.aop.Before;
import com.jfinal.core.Controller;
import com.jfinal.ext.interceptor.POST;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.tx.Tx;
import com.jfinal.upload.UploadFile;
import com.qiniu.api.auth.AuthException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;
import java.util.Date;
import org.json.JSONException;
import top.jnaw.jee.platform.Consts;
import top.jnaw.jee.platform.Consts.Result;
import top.jnaw.jee.platform.model.ExportFactory;
import top.jnaw.jee.platform.model.Files;
import top.jnaw.jee.platform.model.Users;
import top.jnaw.jee.utils.Dates;
import top.jnaw.jee.utils.Excel;
import top.jnaw.jee.utils.Https;
import top.jnaw.jee.utils.Log;
import top.jnaw.jee.utils.ModelResult;
import top.jnaw.jee.utils.Models;
import top.jnaw.jee.utils.Shiros;
import top.jnaw.jee.utils.Strings;
import top.jnaw.jee.utils.qiniu.ExecuteResult;
import top.jnaw.jee.utils.qiniu.QiniuUtil;
import top.jnaw.jee.utils.wechat.Wechats;

public class FileController extends Controller {

  /**
   * -> file <p> <- result, data: {id, url}
   */
  @Before(POST.class)
  public void addFile() {
    upload(false, false);
  }

  /**
   * -> file <p> <- result, data: {id, url, thumb}
   */
  @Before(POST.class)
  public void addImage() {
    upload(true, false);
  }

  public void db2e() {
    JSONObject req = Strings.toJSONObject(this);
    final String table = Strings.getString(req, "table", "");
    final String select = Strings.getString(req, "select", "");

    ModelResult result = new ModelResult();

    if (StrKit.notBlank(table)) {
      Excel excel = new Excel(Db.use(), table, select);
      String fileName = new Date().getTime() + ".xlsx";
      excel.toFile(Consts.UPLOAD_FOLDER + fileName);

      result.setResult(Result.kSuccess);
      result.setObject(Consts.UPLOAD_URL_BASE + fileName);
    }

    renderJson(result.toJson());
  }

  public void list() {
    JSONObject req = Strings.toJSONObject(this);
    final String type = Strings.getString(req, "type", "all");
    final int page = Strings.getInt(req, "page", Consts.DEFAULT_PAGE);
    final int size = Strings.getInt(req, "size", Consts.DEFAULT_PAGE_SIZE);
    final String title = Strings.getString(req, "title", "");
    final int id = Strings.getInt(req, "id", Consts.DEFAULT_BAD_ID);
    int uid = Strings.getInt(req, "uid", Consts.DEFAULT_BAD_ID);
    if (uid < 0) {
      Users user = Users.getByUsername(Shiros.getUser());
      uid = (user != null) ? user.getId() : Consts.DEFAULT_BAD_ID;
    }
    ModelResult result = Files.list(page, size, type, title, uid, id);
    switch (type) {
      case "all": {
        JSONObject object = (JSONObject) result.getObject();
        renderJson(Strings.formatJsonDateTime(Strings.formatPage(object)));
        break;
      }
      case "model": {
        JSONObject object = (JSONObject) result.getObject();
        renderJson(Strings.formatJsonDateTime(Strings.formatPage(object)));
        break;
      }
      default: {
        renderJson(result.toJson());
      }
    }
  }

  public void query() {
    ModelResult result = new ModelResult(Result.kBadParam);
    JSONObject req = Strings.toJSONObject(this);
    final int id = Strings.getInt(req, "id", Consts.DEFAULT_PAGE);
    if (id > 0) {
      result = Files.query(id);
    }
    renderJson(result.toJson());
  }

  public void e2db() {
    JSONObject req = Strings.toJSONObject(this);

    final int id = Strings.getInt(req, "id", Consts.DEFAULT_BAD_ID);
    final int sheet = Strings.getInt(req, "sheet", 0);
    final int title = Strings.getInt(req, "title", 0);
    final boolean overwrite = Strings.getboolean(req, "overwrite", false);
    final String table = Strings.getString(req, "table", "");

    if (id < 0 || StrKit.isBlank(table)) {
      renderJson(Models.toJson(Result.kBadParam));
      return;
    }

    Files file = Files.dao.findById(id);
    if (null == file) {
      renderJson(Models.toJson(Result.kNull));
      return;
    } else if (!file.getSuffiix().contains("xls")) {
      renderJson(Models.toJson(Result.kBadParam));
      return;
    }

    try {
      String path = file.getUrl()
          .replace(Consts.UPLOAD_URL_BASE, Consts.UPLOAD_FOLDER);

      File target = new File(path);
      Excel excel = new Excel(target);
      excel.pick(sheet, title);

      excel.toDB(Db.use(), "esd_" + table, overwrite);

      renderJson(Models.toJson(Result.kSuccess));
    } catch (Exception e) {
      e.printStackTrace();
      renderJson(Models.toJson(Result.kBadCheck));
    }

  }

  @Before(Tx.class)
  public void delete() {
    ModelResult result = new ModelResult(Result.kBadParam);

    JSONObject req = Strings.toJSONObject(this);

    final int id = Strings.getInt(req, "id", Consts.DEFAULT_BAD_ID);

    Files file = Files.dao.findById(id);

    if (null != file) {

      if (Files.dao.deleteById(id)) {
        QiniuUtil qiniuUtil = new QiniuUtil();
        if (null != file.getThumb()) {
          qiniuUtil.deleteFile(file.getThumb().replace(Consts.domain, ""));
        }
        if (null != file.getUrl()) {
          qiniuUtil.deleteFile(file.getUrl().replace(Consts.domain, ""));
        }
        String path =
            Consts.UPLOAD_FOLDER + file.getUid() + "/" + file.getName();

        File f = new File(path);

        if (f.delete()) {

          result.setResult(Result.kSuccess);
          //图片删除缩略图
          if ("image".equals(file.getFileType())) {

//            start = file.getThumb().indexOf("uploaded") + 9;
//            end = file.getThumb().length();
            path += ".thumb.jpg";

            f = new File(path);
            result.setResult(f.delete()
                             ? Result.kSuccess
                             : Result.kModelDeleteError);
          }
        }

      }
    }
//    if (null != file) {
//
//      if (Files.dao.deleteById(id)) {
//
//        //删除附件
//        int start = file.getUrl().indexOf("uploaded") + 9;
//        int end = file.getUrl().length();
//
//        String path = Consts.UPLOAD_FOLDER + file.getUrl()
//            .substring(start, end);
//
//        File f = new File(path);
//
//        if (f.delete()) {
//
//          result.setResult(Result.kSuccess);
//          //图片删除缩略图
//          if ("image".equals(file.getFileType())) {
//
//            start = file.getThumb().indexOf("uploaded") + 9;
//            end = file.getThumb().length();
//            path = Consts.UPLOAD_FOLDER + file.getThumb().substring(start, end);
//
//            f = new File(path);
//            result.setResult(f.delete()
//                             ? Result.kSuccess
//                             : Result.kModelDeleteError);
//          }
//        }
//
//      }
//    }

    renderJson(result.toJson());
  }

  public void getImage() {
    ModelResult result = new ModelResult(Result.kBadParam);

    JSONObject req = Strings.toJSONObject(this);
    final String media = req.containsKey("id") ? req.getString("id") : "";

    if (StrKit.isBlank(media)) {
      renderJson(result.toJson());
      return;
    }

    File mediaFolder = new File(Consts.UPLOAD_FOLDER + "wechat");
    boolean t = mediaFolder.exists();
    if (!t) {
      t = mediaFolder.mkdirs();
    }

    if (t) {
      String file =
          Consts.UPLOAD_FOLDER + "wechat/" + Dates.now().getTime() + ".jpg";
      File target = Wechats.getMedia(media, file);

      if (null != target) {
        QiniuUtil qiniuUtil = new QiniuUtil();
        ExecuteResult<String> executeResult = null;
        try {
          executeResult = qiniuUtil.uploadFile(target, ".jpg");
        } catch (AuthException e) {
          e.printStackTrace();
        } catch (JSONException e) {
          e.printStackTrace();
        }
        result = Files.add(-1, target, media + ".jpg", "wechat", true,
            executeResult.getResult(), false);
      } else {
        result.setResult(Result.kNull);
      }
    } else {
      result.setResult(Result.kBadCheck);
    }

    renderJson(result.toJson());
  }

  private void upload(boolean image, boolean theme) {
    ModelResult result = new ModelResult(Result.kBadParam);
    ExecuteResult<String> executeResult;
    JSONObject json = new JSONObject();
    result.setObject(json);
    Users user = Users.getByUsername(Shiros.getUser());
    int uid = (user != null) ? user.getId() : Consts.DEFAULT_BAD_ID_1;
    UploadFile file;

    try {
      file = getFile("file");
    } catch (Exception e) {
      // [Neo] empty
      renderJson(Models.toJsonObject(json, Result.kException));
      return;
    }
    if (null != file) {
      String from = getFrom();
      String orgName = file.getOriginalFileName();
      String suffix = " ";
      int range = orgName.lastIndexOf(".");
      if (range != -1) {
        suffix = orgName.substring(range);
      }
      String name = Dates.now().getTime() + suffix;

      String mid = ("wechat".equals(from)) ? "wechat" : String.valueOf(uid);
      String folderPath = Consts.UPLOAD_FOLDER + mid;
      File folder = new File(folderPath);

      if (!folder.exists()) {
        if (!folder.mkdirs()) {
          result.setResult(Result.kBadCheck);
          renderJson(result.toJson());
          return;
        }
      }

      String targetPath = folderPath + "/" + name;
      String url = Consts.UPLOAD_URL_BASE + mid + "/" + name;
      File target = new File(targetPath);

      FileChannel in = null;
      FileChannel out = null;

      try {
        target.createNewFile();
        in = new FileInputStream(file.getFile()).getChannel();
        out = new FileOutputStream(target).getChannel();

        long size = in.size();
        long done = in.transferTo(0, size, out);

        if (done != size) {
          result.setResult(Result.kFileCopyError);
          renderJson(result.toJson());
          return;
        }
        // QiniuUtil qiniuUtil = new QiniuUtil();
        // executeResult = qiniuUtil.uploadFile(target, suffix);
        // Log.w("QiNiu:" + executeResult.getResult());
        result = Files
            .add(uid, target, orgName, from, image, url, theme);
      } catch (Exception e) {
        result.setResult(Result.kException);
        e.printStackTrace();
      } finally {
        try {
          if (null != in) {
            in.close();
          }

          if (null != out) {
            out.close();
          }

        } catch (Exception e) {
          result.setResult(Result.kException);
        }
      }
    }

    renderJson(result.toJson());
  }


  @Before(POST.class)
  public void db2excle() {

    ModelResult result = new ModelResult(Result.kBadParam);
    JSONObject req = Strings.toJSONObject(this);

    final String type = Strings.getString(req, "type", "");
    final String fields = Strings.getString(req, "fields", "");
    final JSONArray ids = Strings.getJSONArray(req, "ids", null);

    Users user = Users.getByUsername(Shiros.getUser());
    int uid = (null != user) ? user.getId() : Consts.DEFAULT_BAD_ID;

    if (StrKit.notBlank(type, fields) && uid > 0) {
      Excel e = ExportFactory
          .createOperation(type, fields, ids);

      String fileName = new Date().getTime() + ".xlsx";
      e.toFile(Consts.UPLOAD_FOLDER + fileName);
      result.setResult(Result.kSuccess);
      result.setObject(Consts.UPLOAD_URL_BASE + fileName);
    }
    renderJson(result.toJson());
  }

  /**
   * excle在线预览
   */
  public void exclePreview() {
    ModelResult result = new ModelResult(Consts.Result.kBadParam);

    JSONObject req = Strings.toJSONObject(this);

    final int fid = req.containsKey("fid")
                    ? req.getIntValue("fid")
                    : Consts.DEFAULT_BAD_ID;
    final int lines = req.containsKey("lines")
                      ? req.getIntValue("lines")
                      : 10;
    if (fid > 0) {
      Files file = Files.dao.findById(fid);

//      int start = file.getUrl().indexOf("uploaded") + 9;
//      int end = file.getUrl().length();
//
//      String path = Consts.UPLOAD_FOLDER + file.getUrl()
//          .substring(start, end);
      int start = file.getUrl().indexOf("top/") + 15;
      int end = file.getUrl().length();

      String path = Consts.UPLOAD_QINIU + file.getUrl()
          .substring(start, end);

      try {

        Excel excel = new Excel(Https.getFile(file.getUrl(), path));
        Log.e("excel::" + excel.toString());
        JSONArray array = excel.preview(lines);
        result.setResult(Result.kSuccess);
        result.setObject(array);
      } catch (Exception e) {
        result.setResult(Result.kException);
      }
    }

    renderJson(result.toJson());
  }

  private String getFrom() {
    return getControllerKey().contains("wechat") ?
           Consts.FROM_WECHAT :
           Consts.FROM_APP;
  }

  @Before(POST.class)
  public void addRichText() {

    ModelResult result = new ModelResult(Result.kBadParam);

    JSONObject json = new JSONObject();
    result.setObject(json);

    final String username = Shiros.getUser();
    Users user = Users.getByUsername(username);
    int uid = (null != user) ? user.getId() : Consts.DEFAULT_BAD_ID;

    UploadFile file;

    try {
      file = getFile("upload");
    } catch (Exception e) {
      // [Neo] empty
      renderJson(Models.toJsonObject(json, Result.kException));
      return;
    }

    if (null != file) {
      String from = getFrom();
      String orgName = file.getFileName();
      String suffix = orgName.substring(orgName.lastIndexOf("."));
      String name = Dates.now().getTime() + suffix;

      String mid = ("wechat".equals(from)) ? "wechat" : String.valueOf(uid);
      String folderPath = Consts.UPLOAD_FOLDER + mid;
      File folder = new File(folderPath);

      if (!folder.exists()) {
        if (!folder.mkdirs()) {
          result.setResult(Result.kBadCheck);
          renderJson(result.toJson());
          return;
        }
      }

      String targetPath = folderPath + "/" + name;
      File target = new File(targetPath);

      FileChannel in = null;
      FileChannel out = null;

      try {
        target.createNewFile();
        in = new FileInputStream(file.getFile()).getChannel();
        out = new FileOutputStream(target).getChannel();

        long size = in.size();
        long done = in.transferTo(0, size, out);

        if (done != size) {
          result.setResult(Result.kFileCopyError);
          renderJson(result.toJson());
          return;
        }

        result = Files.addimg(uid, target, orgName, from, true);

      } catch (Exception e) {
        result.setResult(Result.kException);
        e.printStackTrace();
      } finally {
        try {
          if (null != in) {
            in.close();
          }

          if (null != out) {
            out.close();
          }

        } catch (Exception e) {
          result.setResult(Result.kException);
        }
      }
    }

    if (result.fine()) {
      json.put("uploaded", true);
      JSONObject object = (JSONObject) result.getObject();
      json.put("url", object.get("url"));
    }

    renderJson(json);
  }

}
